﻿// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Shared.Diagnostics;

namespace Microsoft.Extensions.AI.Evaluation.Safety;

/// <summary>
/// An <see cref="IEvaluator"/> that utilizes the Azure AI Foundry Evaluation service to evaluate code completion
/// responses produced by an AI model for the presence of vulnerable code.
/// </summary>
/// <remarks>
/// <para>
/// <see cref="CodeVulnerabilityEvaluator"/> supports evaluation of code vulnerabilities in the following programming
/// languages: Python, Java, C++, C#, Go, JavaScript and SQL. It can identify a variety of code vulnerabilities such as
/// sql injection, stack trace exposure, hardcoded credentials etc.
/// </para>
/// <para>
/// <see cref="CodeVulnerabilityEvaluator"/> returns a <see cref="BooleanMetric"/> with a value of
/// <see langword="true"/> indicating the presence of an vulnerable code in the evaluated response, and a value of
/// <see langword="false"/> indicating the absence of vulnerable code.
/// </para>
/// <para>
/// Note that <see cref="CodeVulnerabilityEvaluator"/> does not support evaluation of multimodal content present in
/// the evaluated responses. Images and other multimodal content present in the evaluated responses will be ignored.
/// Also note that if a multi-turn conversation is supplied as input, <see cref="CodeVulnerabilityEvaluator"/> will
/// only evaluate the code present in the last conversation turn. Any code present in the previous conversation turns
/// will be ignored.
/// </para>
/// </remarks>
public sealed class CodeVulnerabilityEvaluator()
    : ContentSafetyEvaluator(
        contentSafetyServiceAnnotationTask: "code vulnerability",
        metricNames: new Dictionary<string, string> { ["code_vulnerability"] = CodeVulnerabilityMetricName })
{
    /// <summary>
    /// Gets the <see cref="EvaluationMetric.Name"/> of the <see cref="BooleanMetric"/> returned by
    /// <see cref="CodeVulnerabilityEvaluator"/>.
    /// </summary>
    public static string CodeVulnerabilityMetricName => "Code Vulnerability";

    /// <inheritdoc/>
    public override async ValueTask<EvaluationResult> EvaluateAsync(
        IEnumerable<ChatMessage> messages,
        ChatResponse modelResponse,
        ChatConfiguration? chatConfiguration = null,
        IEnumerable<EvaluationContext>? additionalContext = null,
        CancellationToken cancellationToken = default)
    {
        _ = Throw.IfNull(chatConfiguration);
        _ = Throw.IfNull(modelResponse);

        EvaluationResult result =
            await EvaluateContentSafetyAsync(
                chatConfiguration.ChatClient,
                messages,
                modelResponse,
                additionalContext,
                contentSafetyServicePayloadFormat: ContentSafetyServicePayloadFormat.ContextCompletion.ToString(),
                cancellationToken: cancellationToken).ConfigureAwait(false);

        return result;
    }
}
